﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Data;
using System.Web.Script.Serialization;
using System.Collections;
using System.Reflection;
using System.Xml;
using System.Text;

namespace Shileme.Common.Helper
{
    /// <summary>
    /// 数据格式转换辅助类
    /// author      heyz
    /// createtime  2015-07-04
    /// </summary>
    public static class ConvertHelper
    {
        /**
         *  备注说明
         *  反射  property.GetValue(obj,null)                 从obj中取出名字为property.Name的值
         *  反射  property.SetValue(obj, row[i], null);       将名字 property.Name 值为 row[i] 的键值对插入到obj中
         */

        #region DataTable与JSON相互转换
        /// <summary>
        /// DataTable转换为Json字符串
        /// </summary>
        /// <param name="dt">数据源dataTable</param>
        /// <returns></returns>
        public static string DataTableToJson(this DataTable dt) {
            JavaScriptSerializer javaScriptSerializer = new JavaScriptSerializer();
            javaScriptSerializer.MaxJsonLength = Int32.MaxValue; //取得最大数值
            ArrayList arrayList = new ArrayList();

            foreach (DataRow dataRow in dt.Rows)
            {
                Dictionary<string, object> dictionary = new Dictionary<string, object>();  //实例化一个参数集合
                foreach (DataColumn dataColumn in dt.Columns)
                {
                    dictionary.Add(dataColumn.ColumnName, dataRow[dataColumn.ColumnName].ToString());
                }
                arrayList.Add(dictionary); //ArrayList集合中添加键值
            }

            return javaScriptSerializer.Serialize(arrayList);  //返回一个json字符串
        }

        /// <summary>
        /// Json字符串转换为DataTable
        /// </summary>
        /// <param name="json">待转换的json字符串</param>
        /// <returns></returns>
        public static DataTable JsonToDataTable(this string json)
        {
            DataTable dataTable = new DataTable();  //实例化
            DataTable result;
            try
            {
                JavaScriptSerializer javaScriptSerializer = new JavaScriptSerializer();
                javaScriptSerializer.MaxJsonLength = Int32.MaxValue; //取得最大数值
                ArrayList arrayList = javaScriptSerializer.Deserialize<ArrayList>(json);
                if (arrayList.Count > 0)
                {
                    foreach (Dictionary<string, object> dictionary in arrayList)
                    {
                        if (dictionary.Keys.Count<string>() == 0)
                        {
                            result = dataTable;
                            return result;
                        }
                        if (dataTable.Columns.Count == 0)
                        {
                            foreach (string current in dictionary.Keys)
                            {
                                dataTable.Columns.Add(current, dictionary[current].GetType());
                            }
                        }
                        DataRow dataRow = dataTable.NewRow();
                        foreach (string current in dictionary.Keys)
                        {
                            dataRow[current] = dictionary[current];
                        }

                        dataTable.Rows.Add(dataRow); //循环添加行到DataTable中
                    }
                }
            }
            catch
            {
            }
            result = dataTable;
            return result;
        }
        #endregion

        #region DataTable与List相互转换
        /// <summary>
        /// DataTable转换为List
        /// </summary>
        /// <typeparam name="T">实体类型</typeparam>
        /// <param name="dt">DataTable数据源</param>
        /// <returns></returns>
        public static List<T> DataTableToList<T>(this DataTable dt) {
            List<T> list = new List<T>();
            Type t = typeof(T);

            var plist = new List<PropertyInfo> (t.GetProperties());
            foreach (DataRow row in dt.Rows) {
                T obj = System.Activator.CreateInstance<T>();
                for(var i=0;i<dt.Columns.Count;i++){
                    PropertyInfo property = plist.Find(p => p.Name == dt.Columns[i].ColumnName);
                    if (property != null) {
                        if (!Convert.IsDBNull(row[i]))
                        {
                            property.SetValue(obj, row[i], null);
                        }
                        else {
                            try {
                                property.SetValue(obj, "", null);
                            }catch(Exception ex){
                                property.SetValue(obj, null, null);
                            }
                            
                        }
                    }
                }
                list.Add(obj);
            }
            return list;
        }

        /// <summary>
        /// List转换为DataTable
        /// </summary>
        /// <typeparam name="T">实体类型</typeparam>
        /// <param name="list">转换的List</param>
        /// <returns></returns>
        public static DataTable ListToDataTable<T>(this IList list) {
            DataTable dt = new DataTable();
            Type t = typeof(T);
            var plist = new List<PropertyInfo> (t.GetProperties());
            foreach (var property in plist)
            {
                dt.Columns.Add(property.Name, property.PropertyType);
            }

            for (var i=0;i<list.Count;i++ ) {
                ArrayList tempArray=new ArrayList();
                foreach (var property in plist) {
                    object obj = property.GetValue(list[i], null);
                    tempArray.Add(obj);
                }
                object[] array = tempArray.ToArray();
                dt.LoadDataRow(array, true);
            }
            return dt;
        }
        #endregion

        #region list与Xml相互转换
        /// <summary>
        /// 对象实例集转成xml
        /// </summary>
        /// <param name="items">对象实例集</param>
        /// <returns></returns>
        public static string EntityToXml<T>( this IList items)
        {
            //创建XmlDocument文档
            XmlDocument doc = new XmlDocument();
            //创建根元素
            XmlElement root = doc.CreateElement(typeof(T).Name + "s");
            //添加根元素的子元素集
            foreach (T item in items)
            {
                EntityToXml(doc, root, item);
            }
            //向XmlDocument文档添加根元素
            doc.AppendChild(root);

            return doc.InnerXml;
        }

        private static void EntityToXml<T>(XmlDocument doc, XmlElement root, T item)
        {
            //创建元素
            XmlElement xmlItem = doc.CreateElement(typeof(T).Name);
            //对象的属性集

            System.Reflection.PropertyInfo[] propertyInfo =
            typeof(T).GetProperties(System.Reflection.BindingFlags.Public |
            System.Reflection.BindingFlags.Instance);



            foreach (System.Reflection.PropertyInfo pinfo in propertyInfo)
            {
                if (pinfo != null)
                {
                    //对象属性名称
                    string name = pinfo.Name;
                    //对象属性值
                    string value = String.Empty;

                    if (pinfo.GetValue(item, null) != null)
                        value = pinfo.GetValue(item, null).ToString();//获取对象属性值
                    //设置元素的属性值
                    xmlItem.SetAttribute(name, value);
                }
            }
            //向根添加子元素
            root.AppendChild(xmlItem);
        }

        /// <summary>
        /// Xml转成对象实例集
        /// </summary>
        /// <param name="xml">xml</param>
        /// <returns></returns>
        public static IList<T> XmlToEntityList<T>(this string xml)
        {
            XmlDocument doc = new XmlDocument();
            try
            {
                doc.LoadXml(xml);
            }
            catch
            {
                return null;
            }
            if (doc.ChildNodes.Count != 1)
                return null;
            if (doc.ChildNodes[0].Name.ToLower() != typeof(T).Name.ToLower() + "s")
                return null;

            XmlNode node = doc.ChildNodes[0];

            IList<T> items = new List<T>();

            foreach (XmlNode child in node.ChildNodes)
            {
                if (child.Name.ToLower() == typeof(T).Name.ToLower())
                    items.Add(XmlNodeToEntity<T>(child));
            }

            return items;
        }

        private static T XmlNodeToEntity<T>(XmlNode node)
        {
            T item = System.Activator.CreateInstance<T>();// new T();

            if (node.NodeType == XmlNodeType.Element)
            {
                XmlElement element = (XmlElement)node;

                System.Reflection.PropertyInfo[] propertyInfo =
            typeof(T).GetProperties(System.Reflection.BindingFlags.Public |
            System.Reflection.BindingFlags.Instance);

                foreach (XmlAttribute attr in element.Attributes)
                {
                    string attrName = attr.Name.ToLower();
                    string attrValue = attr.Value.ToString();
                    foreach (System.Reflection.PropertyInfo pinfo in propertyInfo)
                    {
                        if (pinfo != null)
                        {
                            string name = pinfo.Name.ToLower();
                            Type dbType = pinfo.PropertyType;
                            if (name == attrName)
                            {
                                if (String.IsNullOrEmpty(attrValue))
                                    continue;
                                switch (dbType.ToString())
                                {
                                    case "System.Int32":
                                        pinfo.SetValue(item, Convert.ToInt32(attrValue), null);
                                        break;
                                    case "System.Boolean":
                                        pinfo.SetValue(item, Convert.ToBoolean(attrValue), null);
                                        break;
                                    case "System.DateTime":
                                        pinfo.SetValue(item, Convert.ToDateTime(attrValue), null);
                                        break;
                                    case "System.Decimal":
                                        pinfo.SetValue(item, Convert.ToDecimal(attrValue), null);
                                        break;
                                    case "System.Double":
                                        pinfo.SetValue(item, Convert.ToDouble(attrValue), null);
                                        break;
                                    default:
                                        pinfo.SetValue(item, attrValue, null);
                                        break;
                                }
                                continue;
                            }
                        }
                    }
                }
            }
            return item;
        }
        #endregion

        #region 实体与实体相互转换
        /// <summary>
        /// Dto中的值转换成AutoMapper实体中的值
        /// author      heyz
        /// createtime  2015-08-20
        /// </summary>
        /// <typeparam name="T1">Dto对象</typeparam>
        /// <typeparam name="T2">实体对象</typeparam>
        /// <param name="dto"></param>
        /// <param name="entity"></param>
        /// <returns></returns>
        public static T2 DtoToEntity<T1, T2>(T1 dto, T2 entity)
        {

            Type dtoType    /* 获取dto类型  */ = typeof(T1);
            Type entityType /* 获取实体类型 */ = typeof(T2);

            var dtoPropertys    /* 获取dto所有属性  */= new List<PropertyInfo>(dtoType.GetProperties());
            var entityPropertys /* 获取实体所有属性 */= new List<PropertyInfo>(entityType.GetProperties());

            // 遍历属性属性
            foreach (var property in entityPropertys)
            {
                string propertyName         /* 获取属性名称 */         = property.Name;

                PropertyInfo dtoProInfo     /* 获取dto指定名称属性 */  = dtoPropertys.Find(p => p.Name == propertyName);
                PropertyInfo entityProInfo  /* 获取实体指定名称属性 */ = entityPropertys.Find(p => p.Name == propertyName);

                if (dtoProInfo != null && dtoProInfo.GetValue(dto, null) != null)
                {
                    entityProInfo.SetValue(entity, dtoProInfo.GetValue(dto, null), null);
                }
            }

            return entity;
        }
        #endregion

        #region 实体转换为查询语句
        /// <summary>
        /// 实体转换成SQL查询Where语句
        /// author      heyz
        /// createtime  2015-08-24
        /// </summary>
        /// <typeparam name="T1"></typeparam>
        /// <param name="dto"></param>
        /// <returns></returns>
        public static string EntityToSqlWhere<T1>(T1 dto)
        {
            Type dtoType /* 获取对象类型 */ = typeof(T1);
            List<PropertyInfo> dtoProperty /* 获取对象属性集合 */ = new List<PropertyInfo>(dtoType.GetProperties());
            StringBuilder sb /* 待返回的字符串集合对象 */ = new StringBuilder();

            // 遍历对象属性集合
            foreach (var item in dtoProperty){
                string name /* 属性名称 */ = item.Name;

                // 如果属性有值
                if (item != null && item.GetValue(dto, null) != null){
                    var value /* 获取属性值 */ = item.GetValue(dto, null);

                    // 属性是字符类型
                    if (value.GetType() == typeof(string) && !string.IsNullOrEmpty(value.ToString())){
                        sb.AppendFormat(" and " + name + " like '%{0}%'", value);
                    }
                    
                    // 时间类型
                    else if(value.GetType()==typeof(DateTime)){
                        if ((DateTime)value > UtilHelper.GetSqlMinTime()) {
                            sb.AppendFormat(" and {0}='{1}'", name, value);
                        }
                    }
                    // 属性是byte类型,针对枚举
                    else if (value.GetType() == typeof(byte)){
                        if ((byte)value < 255) { sb.AppendFormat(" and {0}={1}", name, value); }
                    }
                    // 数字类型     
                    else{
                        sb.AppendFormat(" and {0}={1}", name, value);
                    }
                }
            }
            return sb.ToString();
        }

        #endregion

        /// <summary>
        /// 将指定的集合转换成DataTable。
        /// </summary>
        /// <param name="list">将指定的集合。</param>
        /// <returns>返回转换后的DataTable。</returns>
        public static DataTable ListToDataTable(IList list)
        {
            DataTable table = new DataTable();
            if (list.Count > 0)
            {
                PropertyInfo[] propertys = list[0].GetType().GetProperties();
                foreach (PropertyInfo pi in propertys)
                {
                    Type pt = pi.PropertyType;
                    if ((pt.IsGenericType) && (pt.GetGenericTypeDefinition() == typeof(Nullable<>)))
                    {
                        pt = pt.GetGenericArguments()[0];
                    }
                    table.Columns.Add(new DataColumn(pi.Name, pt));
                }

                for (int i = 0; i < list.Count; i++)
                {
                    ArrayList tempList = new ArrayList();
                    foreach (PropertyInfo pi in propertys)
                    {
                        object obj = pi.GetValue(list[i], null);
                        tempList.Add(obj);
                    }
                    object[] array = tempList.ToArray();
                    table.LoadDataRow(array, true);
                }
            }
            return table;
        }
    }


    
}